﻿using System;
using System.Linq;
using FluentValidation.TestHelper;
using GiveAQuiz.Web.Membership;
using GiveAQuiz.Web.Models;
using GiveAQuiz.Web.Validation;
using Moq;
using NUnit.Framework;

namespace GiveAQuiz.Web.Tests.Validation
{
  [TestFixture]
  public class RegistrationValidatorTest
  {
    public Mock<IMembershipService> MockMembershipService
    {
      get;
      private set;
    }

    public RegistrationValidator Validator
    {
      get;
      private set;
    }

    [TestFixtureSetUp]
    public void InitializeFixture()
    {
      MockMembershipService = new Mock<IMembershipService>();
      MockMembershipService.SetupGet(m => m.MinPasswordLength).Returns(6);
      Validator = new RegistrationValidator(MockMembershipService.Object);
    }

    [Test]
    public void RuleFor_UserName_should_not_have_error_when_value_is_specified()
    {
      Validator.ShouldNotHaveValidationErrorFor(r => r.UserName, "Foo");
    }

    [Test]
    public void RuleFor_UserName_cannot_be_empty()
    {
      Validator.ShouldHaveValidationErrorFor(r => r.UserName, String.Empty);
    }

    [Test]
    public void RuleFor_UserName_cannot_be_null()
    {
      Validator.ShouldHaveValidationErrorFor(r => r.UserName, null as string);
    }

    [Test]
    public void RuleFor_UserName_cannot_be_blank()
    {
      Validator.ShouldHaveValidationErrorFor(r => r.UserName, "  ");
    }

    [Test]
    public void RuleFor_Password_should_not_have_error_when_value_is_specified()
    {
      Validator.ShouldNotHaveValidationErrorFor(r => r.Password, "password");
    }

    [Test]
    public void RuleFor_Password_cannot_be_empty()
    {
      Validator.ShouldHaveValidationErrorFor(r => r.Password, String.Empty);
    }

    [Test]
    public void RuleFor_Password_cannot_be_null()
    {
      Validator.ShouldHaveValidationErrorFor(r => r.Password, null as string);
    }

    [Test]
    public void RuleFor_Password_cannot_be_blank()
    {
      Validator.ShouldHaveValidationErrorFor(r => r.Password, "  ");
    }

    [Test]
    public void RuleFor_Password_must_be_longer_than_6_characters()
    {
      var model = new RegistrationViewModel() { Password = "12345" };
      var vr = Validator.Validate(model);
      // actually validates against the "Password.Length" property
      Assert.IsNotNull(vr.Errors.FirstOrDefault(vf => vf.PropertyName.Equals("Length")));
    }

    [Test]
    public void RuleFor_Password_should_not_have_error_when_6_or_more_characters()
    {
      var model = new RegistrationViewModel() { Password = "123456" };
      var vr = Validator.Validate(model);
      // actually validates against the "Password.Length" property
      Assert.IsNull(vr.Errors.FirstOrDefault(vf => vf.PropertyName.Equals("Length")));
    }

    [Test]
    public void RuleFor_RepeatPassword_should_not_have_error_when_value_is_specified()
    {
      var model = new RegistrationViewModel() { Password = "password", RepeatPassword = "password" };
      Validator.ShouldNotHaveValidationErrorFor(r => r.RepeatPassword, model);
    }

    [Test]
    public void RuleFor_RepeatPassword_cannot_be_empty()
    {
      Validator.ShouldHaveValidationErrorFor(r => r.RepeatPassword, String.Empty);
    }

    [Test]
    public void RuleFor_RepeatPassword_cannot_be_null()
    {
      Validator.ShouldHaveValidationErrorFor(r => r.RepeatPassword, null as string);
    }

    [Test]
    public void RuleFor_RepeatPassword_cannot_be_blank()
    {
      Validator.ShouldHaveValidationErrorFor(r => r.RepeatPassword, "  ");
    }

    [Test]
    public void RuleFor_RepeatPassword_must_be_longer_than_6_characters()
    {
      var model = new RegistrationViewModel() { Password = "12345", RepeatPassword = "12345" };
      var vr = Validator.Validate(model);
      // actually validates against the "RepeatPassword.Length" property
      Assert.IsNotNull(vr.Errors.FirstOrDefault(vf => vf.PropertyName.Equals("Length")));
    }

    [Test]
    public void RuleFor_RepeatPassword_should_not_have_error_when_6_or_more_characters()
    {
      var model = new RegistrationViewModel() { Password = "123456", RepeatPassword = "123456" };
      var vr = Validator.Validate(model);
      // actually validates against the "RepeatPassword.Length" property
      Assert.IsNull(vr.Errors.FirstOrDefault(vf => vf.PropertyName.Equals("Length")));
    }

    [Test]
    public void Custom_should_not_have_error_when_Password_and_RepeatPassword_are_equal()
    {
      var model = new RegistrationViewModel() { Password = "password", RepeatPassword = "password" };
      Validator.ShouldNotHaveValidationErrorFor(r => r.RepeatPassword, model);
    }

    [Test]
    public void Custom_should_have_error_when_Password_and_RepeatPassword_are_not_equal()
    {
      var model = new RegistrationViewModel() { Password = "password", RepeatPassword = "wrong_password" };
      Validator.ShouldHaveValidationErrorFor(r => r.RepeatPassword, model);
    }

    [Test]
    public void RuleFor_Email_should_not_have_error_when_email_is_valid()
    {
      Validator.ShouldNotHaveValidationErrorFor(r => r.Email, "foo@bar.com");
    }

    [Test]
    public void RuleFor_Email_should_have_error_when_email_is_invalid()
    {
      Validator.ShouldHaveValidationErrorFor(r => r.Email, "foobar.com");
    }
  }
}
